import math

import matplotlib.pyplot as plt
import numpy as np

import datetime
import json
import pickle
import random

import numpy
import matplotlib
import numpy as np
import scipy
from sklearn import metrics, ensemble
from sklearn.metrics import mean_absolute_error
from sklearn.neighbors import RadiusNeighborsRegressor
from sklearn.neural_network import MLPRegressor
from sklearn.preprocessing import OneHotEncoder, MinMaxScaler
import pymysql
from django.core import serializers
from django.http import JsonResponse
from django.shortcuts import render
from sklearn.svm import SVR
from sklearn import linear_model
from django.views.decorators.csrf import csrf_exempt

# Create your views here.
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_http_methods
from sklearn.tree import DecisionTreeRegressor


def predict(cang):
    # params = json.loads(request.body)["params"]
    # lineID = params["lineID"]
    # stationID = params["stationID"]
    # date = params["date"]
    # methodList = params["methods"][1:-1].replace('"','').split(',')
    response = {}
    response["station"] = {}
    response["line"] = {}
    lineID = '1'
    stationID = '303'
    date = '2018-06-01'
    methodList = ["RandomForest"]
    dayType = datetime.datetime.strptime(date, "%Y-%m-%d").weekday() + 1
    for method in methodList:
        print(method)
        m = datetime.timedelta(hours=7)
        station_pre_flow = list()
        line_pre_flow = list()
        station_test_flow = list()
        line_test_flow = list()
        while m <= datetime.timedelta(hours=23):
            station_data = get_station_data(m, stationID, date)
            line_data = get_line_data(m, lineID, date)
            # station_res = train(station_data, method,)
            line_res = train(line_data, method, cang)
            # station_test_flow.append(station_res[0])
            # station_pre_flow.append(station_res[1])
            line_test_flow.append(line_res[0])
            line_pre_flow.append(line_res[1])
            m = m + datetime.timedelta(minutes=5)
        # station_mse = metrics.mean_squared_error(station_test_flow, station_pre_flow)
        # station_rmse = np.sqrt(station_mse)
        # station_mae = metrics.mean_absolute_error(station_test_flow, station_pre_flow)
        line_mse = metrics.mean_squared_error(line_test_flow, line_pre_flow)
        line_rmse = np.sqrt(line_mse)
        line_mae = metrics.mean_absolute_error(line_test_flow, line_pre_flow)
        # response["station"][method] = {
        #     "preflow": station_pre_flow, "mse": int(station_mse), "rmse": int(station_rmse), "mae": int(station_mae)
        # }
        response["line"][method] = {
            "preflow": line_pre_flow, "mse": int(line_mse), "rmse": int(line_rmse), "mae": int(line_mae)
        }

    # response["station"]["stationName"] = stationID
    # response["station"]["stationID"] = stationID
    # response["station"]["date"] = date
    # response["station"]["testflow"] = station_test_flow

    response["line"]["lineName"] = str(lineID) + "号线"
    response["line"]["lineID"] = lineID
    response["line"]["date"] = date
    response["line"]["testflow"] = line_test_flow

    return response["line"]["RandomForest"], response["line"]["testflow"]


def day_type(day):
    if 1 <= day <= 5:
        return 0
    else:
        return 1
    return 1


def get_station_data(time, stationID, date):
    conn = pymysql.connect(host='localhost',  # 连接名称
                           user='root',  # 用户名
                           passwd='q19723011',  # 密码
                           port=3306,  # 端口，默认为3306
                           db='month6',  # 数据库
                           charset='utf8',  # 字符编码
                           )
    cur = conn.cursor()  # 生成游标对象
    dataProcess = []
    start_time = "".join(str(time - datetime.timedelta(minutes=30)).split(':')[:3])
    sql = "select * from station_time_flow where time >= %s and  time <= %s and stationID = %d" \
          % (start_time, "".join(str(time).split(':')[:3]), int(stationID))
    cur.execute(sql)
    datas = list(cur.fetchall())
    ob_dayType = day_type(datetime.datetime.strptime(date, "%Y-%m-%d").date().weekday() + 1)
    ob_data_list = list()
    for i in range(0, len(datas), 7):
        if datas[i][1] == datetime.datetime.strptime(date, "%Y-%m-%d").date():
            ob_data_list = [datas[i][3], datas[i + 1][3],
                            datas[i + 2][3], datas[i + 3][3], datas[i + 4][3],
                            datas[i + 5][3], datas[i + 6][3]]
        elif day_type(datas[i][1].weekday() + 1) == ob_dayType:
            data_list = [datas[i][3], datas[i + 1][3],
                         datas[i + 2][3], datas[i + 3][3], datas[i + 4][3],
                         datas[i + 5][3], datas[i + 6][3]]
            dataProcess.append(data_list)
    dataProcess.append(ob_data_list)

    conn.commit()
    cur.close()  # 关闭游标
    conn.close()  # 关闭连接
    return dataProcess


def get_line_data(time, lineID, date):
    conn = pymysql.connect(host='localhost',  # 连接名称
                           user='root',  # 用户名
                           passwd='q19723011',  # 密码
                           port=3306,  # 端口，默认为3306
                           db='month6',  # 数据库
                           charset='utf8',  # 字符编码
                           )
    cur = conn.cursor()  # 生成游标对象
    dataProcess = []
    start_time = "".join(str(time - datetime.timedelta(minutes=30)).split(':')[:3])
    sql = "select * from line_time_flow where time >= %s and  time <= %s and lineID = %d" \
          % (start_time, "".join(str(time).split(':')[:3]), int(lineID))
    cur.execute(sql)
    datas = list(cur.fetchall())
    ob_dayType = day_type(datetime.datetime.strptime(date, "%Y-%m-%d").date().weekday() + 1)
    ob_data_list = list()
    for i in range(0, len(datas), 7):
        if datas[i][1] == datetime.datetime.strptime(date, "%Y-%m-%d").date():
            ob_data_list = [datas[i][3], datas[i + 1][3],
                            datas[i + 2][3], datas[i + 3][3], datas[i + 4][3],
                            datas[i + 5][3], datas[i + 6][3]]
        elif day_type(datas[i][1].weekday() + 1) == ob_dayType:
            data_list = [datas[i][3], datas[i + 1][3],
                         datas[i + 2][3], datas[i + 3][3], datas[i + 4][3],
                         datas[i + 5][3], datas[i + 6][3]]
            dataProcess.append(data_list)
    dataProcess.append(ob_data_list)

    conn.commit()
    cur.close()  # 关闭游标
    conn.close()  # 关闭连接
    return dataProcess


def train(datas, method, cang):
    # 处理数据，划分训练集，测试集，归一化处理，独热编码处理
    datas = np.array(datas)
    data_case = datas[:, 0:6]  # 获取特征值
    data_label = datas[:, 6:7]  # 获取标签
    mm = MinMaxScaler()
    data_label_process = mm.fit_transform(data_label)  # 对数据归一化处理
    mm_case = MinMaxScaler()
    data_case_process = mm_case.fit_transform(data_case)  # 对数据归一化处理
    test_data_case = data_case_process[len(data_case_process) - 1:]
    test_data_label = data_label_process[len(data_label_process) - 1:]
    train_data_case = data_case_process[0:len(data_case_process) - 1]
    train_data_label = data_label_process[0:len(data_label_process) - 1]
    # 训练模型
    if method == "BPNN":
        model = MLPRegressor(hidden_layer_sizes=(100, 100), activation='tanh', solver='adam', max_iter=2000,
                             learning_rate='adaptive')  # BP神经网络回归模型
    elif method == "RandomForest":
        model = ensemble.RandomForestRegressor(criterion=cang, n_jobs=-1)
    elif method == "SVR":
        model = SVR(kernel='rbf')
    elif method == "LinearRegression":
        model = linear_model.LinearRegression()
    elif method == "BayesianRidge":
        model = linear_model.BayesianRidge()
    elif method == "KNN":
        model = RadiusNeighborsRegressor()
    elif method == "RegressionTree":
        model = DecisionTreeRegressor(criterion="absolute_error")
    else:
        print("未找到")

    model.fit(train_data_case, train_data_label.ravel())  # 训练模型
    pre_train = model.predict(train_data_case)  # 模型训练集预测
    pre_test = model.predict(test_data_case)  # 模型测试机预测
    pre = mm.inverse_transform(np.append(pre_train, pre_test).reshape(1, -1))[0]  # 反归一化
    return [float(data_label[-1][0]), float(int(pre[-1]))]


if __name__ == '__main__':
    # m_1 = [100, 100]
    # m_2 = [70, 90, 100]
    # m_3 = [70, 80, 90, 60]
    # m_4 = [70, 80, 80, 60]
    m_1 = "squared_error"
    m_2 = "friedman_mse"
    m_3 = "absolute_error"
    m_4 = "poisson"
    y_1, y_or = predict(m_1)
    print("squared_error")
    y_2 = predict(m_2)[0]
    print("friedman_mse")
    y_3 = predict(m_3)[0]
    print("absolute_error")
    y_4 = predict(m_4)[0]
    print("poisson")
    x = np.arange(0, len(y_or), 1)
    # y = []
    # for i in x:
    #     if i <= 0:
    #         y.append(0)
    #     else:
    #         y.append(i)
    # # print(y)
    # # y = (np.exp(x)-np.exp(-x)) / (np.exp(x) + np.exp(-x))

    fig = plt.figure(facecolor="white", figsize=(11, 8))

    poisson = plt.subplot(221)
    poisson.plot(x, y_1["preflow"], label=m_1)
    poisson.plot(x, y_or, label="historical_data")
    poisson.legend()
    poisson.set_ylim(0, 25000)

    squared_error = plt.subplot(222)
    squared_error.plot(x, y_2["preflow"], label=m_2)
    squared_error.plot(x, y_or, label="historical_data")
    squared_error.legend()
    squared_error.set_ylim(0, 25000)

    friedman_mse = plt.subplot(223)
    friedman_mse.plot(x, y_3["preflow"], label=m_3)
    friedman_mse.plot(x, y_or, label="historical_data")
    friedman_mse.legend()
    friedman_mse.set_ylim(0, 25000)

    absolute_error = plt.subplot(224)
    absolute_error.plot(x, y_4["preflow"], label=m_4)
    absolute_error.plot(x, y_or, label="historical_data")
    absolute_error.legend()
    absolute_error.set_ylim(0, 25000)
    # axes.set_ylim(-10, 10)
    # axes.spines['right'].set_color('none')
    # axes.spines['top'].set_color('none')
    # axes.xaxis.set_ticks_position('bottom')
    # axes.spines['bottom'].set_position(('data', 0))
    # axes.yaxis.set_ticks_position('left')
    # axes.spines['left'].set_position(('data', 0))
    # plt.show()
    plt.savefig(r"C:\Users\woniu\Desktop\毕业设计\论文\图片\随机森林模型对比.png", format="png")
    print(m_1, y_1)
    print(m_2, y_2)
    print(m_3, y_3)
    print(m_4, y_4)
